﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace AMOOF {

    public delegate void DelegateSetDataSetVisible(object[] obj);
    public delegate void DelegateAppendToDataSet(object[] obj);
    public delegate void DelegateAppendToDiscreteCTE_VaR(object[] obj);
    public delegate void DelegateUpdate(object obj, string str, object val);

    public partial class AccessData : UserControl {

        private Thread m_importThread;
        private Thread m_displayDataThread;
        private Thread m_displayStatisticsThread;
        private Thread m_displayHistogramThread;

        private DelegateSetDataSetVisible m_delegateSetDataSetVisiblet;
        private DelegateAppendToDataSet m_delegateAppendToDataSet;
        private DelegateAppendToDiscreteCTE_VaR m_delegateAppendToDiscreteCTE_VaR;
        private DelegateUpdate m_delegateUpdate;
        private DelegateUpdateHistogram m_delegateUpdateHistogram;

        public AccessData() {
            InitializeComponent();
           

            m_delegateSetDataSetVisiblet = new DelegateSetDataSetVisible(SetDataSetVisible);
            m_delegateAppendToDataSet = new DelegateAppendToDataSet(AppendValueToDataSet);
            m_delegateAppendToDiscreteCTE_VaR = new DelegateAppendToDiscreteCTE_VaR(AppendValueToDiscreteCTE_VaR);
            m_delegateUpdateHistogram = new DelegateUpdateHistogram(UpdateHistogram);
            m_delegateUpdate = new DelegateUpdate(UpdateField);


            gbxDataSet.Visible = false;
            gbxDataSetStats.Visible = false;
            gbxHistogram.Visible = false;

            

            btnOmitNegatives.Text = "\u2713 Omit Negatives";
            btnOmitNegatives.Active = true;

            btnShiftData.Text = "Shift Data";

            foreach (Control c in pnlHandleNegatives.Controls) {
                if (c is ToggleButton) {
                    c.MouseUp += new MouseEventHandler(ToggleButton_MouseUp);
                }
            }


            btnToggleDataTransform.Text = "Transform Data";
            btnToggleDataTransform.MouseUp += new MouseEventHandler(ToggleTransform_MouseUp);

            btnToggleWeightedProbabilities.Text = "Use Weighted Probabilities";
            btnToggleWeightedProbabilities.MouseUp += new MouseEventHandler(ToggleWeights_MouseUp);

            btnLoadData.Text = "Load Data";
            btnLoadData.MouseClick += new MouseEventHandler(btnLoadData_MouseClick);


            foreach (Control c in Controls) {
                if (c is ToggleButton) {
                    //c.MouseUp += new MouseEventHandler(ToggleButton_MouseUp);
                    //((ToggleButton)c).Active = false;
                }
            }
        }

        private void UpdateHistogram(Bitmap bmp) {
            if (gbxHistogram.InvokeRequired) {
                m_delegateUpdateHistogram = new DelegateUpdateHistogram(UpdateHistogram);
                this.Invoke(m_delegateUpdateHistogram, new object[] { bmp });
            }
            else {
                pnlDiscreteHistogram.BackgroundImage = bmp;
            }
        }

        private void AppendValueToDiscreteCTE_VaR(object[] obj) {
            if (this.InvokeRequired) {
                m_delegateAppendToDiscreteCTE_VaR = new DelegateAppendToDiscreteCTE_VaR(AppendValueToDiscreteCTE_VaR);
                this.Invoke(m_delegateAppendToDiscreteCTE_VaR, new object[] { obj });
            }
            else {

                if (dgvDiscreteCTEVaR.RowCount == 0) {
                    dgvDiscreteCTEVaR.RowCount = 2;
                    dgvDiscreteCTEVaR.Rows[0].HeaderCell.Value = "CTE";
                    dgvDiscreteCTEVaR.Rows[1].HeaderCell.Value = "VaR";
                }
                dgvDiscreteCTEVaR.Rows[0].Cells[(int)obj[0]].Value = String.Format("{0:0.0000####}", (double)obj[1]);
                dgvDiscreteCTEVaR.Rows[1].Cells[(int)obj[0]].Value = String.Format("{0:0.0000####}", (double)obj[2]);
                dgvDiscreteCTEVaR.Invalidate();
                dgvDiscreteCTEVaR.Update();
            }
        }

        private void UpdateField(object obj, string field, object value) {
            if (((Control)obj).InvokeRequired) {
                m_delegateUpdate = new DelegateUpdate(UpdateField);
                this.Invoke(m_delegateUpdate, new object[] { obj, field, value });
            }
            else {
                
                Label label = Reflector.GetField<dynamic>(field, this);
                label.Text = String.Format("{0:0.0000####}", value);
                ((Control)obj).Invalidate();
                ((Control)obj).Update();
            }
        }

        private void AppendValueToDataSet(object[] kvp) {
            if (this.InvokeRequired) {
                m_delegateAppendToDataSet = new DelegateAppendToDataSet(AppendValueToDataSet);
                this.Invoke(m_delegateAppendToDataSet, new object[] {kvp});
            }
            else {
                dgvDataSet.Rows.Add(kvp);
            }
        }

        private void SetDataSetVisible( object[] visible) {
            if (this.InvokeRequired) {
                m_delegateSetDataSetVisiblet = new DelegateSetDataSetVisible(SetDataSetVisible);
                this.Invoke(m_delegateSetDataSetVisiblet, new object[] {visible});
            }
            else {
                dgvDataSet.Rows.Clear();
                gbxDataSet.Visible = (bool)visible[0];
                gbxHistogram.Visible = (bool)visible[0];
                gbxDataSetStats.Visible = (bool)visible[0];
                this.Invalidate();
                this.Refresh();
                this.Update();
            }
        }

        private void ToggleWeights_MouseUp(object sender, MouseEventArgs e) {
            if (MouseIn((Control)sender, e)) {
                ((ToggleButton)sender).Active = ((ToggleButton)sender).Active ? false : true;
                ((ToggleButton)sender).Text = ((ToggleButton)sender).Active ? "\u2713 Use Weighted Probabilities" : "Use Weighted Probabilities";
            }
        }

        private void ToggleTransform_MouseUp(object sender, MouseEventArgs e) {
            if (MouseIn((Control)sender, e)) {
                ((ToggleButton)sender).Active = ((ToggleButton)sender).Active ? false : true;
                ((ToggleButton)sender).Text = ((ToggleButton)sender).Active ? "\u2713 Transform Data" : "Transform Data";
            }
        }


        private bool MouseIn(Control c, MouseEventArgs e) {
            if (e.X > 0 &&
                e.X < c.Width &&
                e.Y > 0 &&
                e.Y < c.Height) {
                    return true;
            }

            return false;
        }

        private void btnLoadData_MouseClick(object sender, MouseEventArgs e) {
            
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "Data Files (*.csv)|*.csv";
            ofd.Title = "Choose a Data Set";
            ofd.Multiselect = false;
            if(ofd.ShowDialog() == DialogResult.OK) {
                System.IO.FileInfo fi = new System.IO.FileInfo(ofd.FileName);
                m_importThread = new Thread(this.Import);
                m_importThread.Start(fi);
            }
        }

        [STAThread]
        private void Import(object obj) {
            DataImport di = new DataImport();
            System.IO.FileInfo fi = (System.IO.FileInfo)obj;
            uint count = di.GetLineCount(fi);
            Dictionary<double, int> data = new Dictionary<double,int>();

            string statement = "";
            bool trigger = false;

            foreach (object o in di.importData(fi)) {
                if (o is string) {
                    if (trigger) { FormAMOOF.Instance.SetProgress(100); }
                    statement = (string)o;
                    trigger = true;
                    FormAMOOF.Instance.SetStatus(statement);
                    FormAMOOF.Instance.SetProgress(0);
                }
                else if (o is uint) {
                    double percent = ((double)((uint)o) / count) * 100;
                    double dec = (percent * 10) % 10;
                    if (dec % 5 == 0) {
                        FormAMOOF.Instance.SetStatus(string.Format("{0}{1:00.00}% complete.",statement, percent));
                        FormAMOOF.Instance.SetProgress((int)percent);
                    }
                }
                else if (o is Dictionary<double, int>) {
                    FormAMOOF.Instance.SetProgress(100);
                    data = (Dictionary<double, int>)o;
                }
            }



            m_displayDataThread = new Thread(this.DisplayData);
            m_displayDataThread.Start(data);

            m_displayStatisticsThread = new Thread(this.DisplayStatistics);
            m_displayStatisticsThread.Start(new Statistics(data).getAllStatistics());

            Histogram histo = new Histogram(data);

            

            m_displayHistogramThread = new Thread(this.DisplayHistogram);
            m_displayHistogramThread.Start(histo);


        }

        [STAThread]
        private void DisplayData(object obj) {
            var data = (Dictionary<double, int>)obj;
            string statement = "Loading Data to form... ";
            uint count = (uint)data.Count;
            int currentVal = 0;
            double _10th = (10.0 / count) * 100;
            int perCount = 1;

            this.SetDataSetVisible(new object[] { true });

            FormAMOOF.Instance.SetStatus(statement);
            FormAMOOF.Instance.SetProgress(0);

            foreach (var kvp in data) {
                this.AppendValueToDataSet(new object[] { kvp.Key, kvp.Value });
                double percent = (((double)currentVal) / count) * 100;
                double dec = (percent * 100) % 100;
                if (Math.Abs((dec - (_10th * perCount))) <= .0000001) {
                    FormAMOOF.Instance.SetStatus(string.Format("{0}{1:00.00}% complete.", statement, percent));
                    FormAMOOF.Instance.SetProgress((int)percent);
                    perCount++;
                }

                currentVal++;

            }

            FormAMOOF.Instance.LoadData(data);
        }

        [STAThread]
        private void DisplayStatistics(object obj) {
            Statistics stats = (Statistics)obj;

            this.UpdateField(gbxDataSetStats, "lblDiscreteMeanValue", stats.Mean);
            this.UpdateField(gbxDataSetStats, "lblDiscreteMedianValue", stats.Median);
            this.UpdateField(gbxDataSetStats, "lblDiscreteQ1Value", stats.FirstQuartile);
            this.UpdateField(gbxDataSetStats, "lblDiscreteQ3Value", stats.ThirdQuartile);
            this.UpdateField(gbxDataSetStats, "lblDiscrete1stMomentValue", stats.PositiveMoments[0]);
            this.UpdateField(gbxDataSetStats, "lblDiscrete2ndMomentValue", stats.PositiveMoments[1]);
            this.UpdateField(gbxDataSetStats, "lblDiscrete3rdMomentValue", stats.PositiveMoments[2]);
            this.UpdateField(gbxDataSetStats, "lblDiscrete4thMomentValue", stats.PositiveMoments[3]);
            this.UpdateField(gbxDataSetStats, "lblDiscreteNegative1stMomentValue", stats.NegativeMoments[0]);
            this.UpdateField(gbxDataSetStats, "lblDiscreteNegative2ndMomentValue", stats.NegativeMoments[1]);
            this.UpdateField(gbxDataSetStats, "lblDiscreteNegative3rdMomentValue", stats.NegativeMoments[2]);
            this.UpdateField(gbxDataSetStats, "lblDiscreteNegative4thMomentValue", stats.NegativeMoments[3]);

            int count = 0;

            

            foreach (var kvp in stats.VaRs) {
                this.AppendValueToDiscreteCTE_VaR(new object[] { count, kvp.Value, stats.CTEs[kvp.Key] });
                count++;
            }

            FormAMOOF.Instance.LoadStatistics(stats);
            
            //this.UpdateField(gbxDataSetStats, "TestMethod", 5);
        }

        private void DisplayHistogram(object obj) {
            Histogram hist = (Histogram)obj;

            this.UpdateHistogram(hist.GetHistogramBitmap(pnlDiscreteHistogram.Size));

            FormAMOOF.Instance.LoadHistogram(hist);
        }

        private void ToggleButton_MouseUp(object sender, MouseEventArgs e) {
            Application.DoEvents();

            if (sender is ToggleButton && !((ToggleButton)sender).Active) {
                if (MouseIn((Control)sender, e)) {
                    foreach (Control c in pnlHandleNegatives.Controls) {
                        if (c is ToggleButton && ((ToggleButton)c).Active) {
                            ((ToggleButton)c).Text = ((ToggleButton)c).Text.Substring(2);
                            ((ToggleButton)c).Active = false;
                        }
                        else if (c is ToggleButton && !((ToggleButton)c).Active) {
                            ((ToggleButton)c).Text = "\u2713 " + ((ToggleButton)c).Text;
                            ((ToggleButton)sender).Active = true;
                        }
                    }
                }
            }
        }

    }
}
